// 本文件用于设计socket的封装，继承、多态
#pragma once

#include <iostream>

#include <sys/types.h>
#include <sys/socket.h>

#include "Log.hpp"
#include "Comm.hpp"
#include "sockaddr.hpp"
#define BUFFERSIZE 1024

const static int default_sockfd = -1;
const static int default_backlog = 5;

// 接口类：用于提供有关套接字编程的相关接口，如创建套接字、绑定套接字、监听、请求连接、获取连接等
class Socket
{
public:
    virtual void SocketCreate() = 0;                              // 创建套接字
    virtual void SocketBind() = 0;                                // 绑定套接字
    virtual void SocketListen(int backlog = default_backlog) = 0; // 监听
    virtual void SocketConnect() = 0;                             // client请求连接
    virtual void SocketAccept() = 0;                              // server获取连接
    virtual int GetSockfd() = 0;                                  // 拿fd
    virtual void Send(std::string sendstr) = 0;                   // 发送数据
    virtual void Recv(std::string &recstr) = 0;                   // 接收数据

public:
    void ServerInit(int backlog = default_backlog)
    {
        SocketCreate();
        SocketBind();
        SocketListen(backlog);
    }
    void ClientInit()
    {
        SocketCreate();
        SocketConnect();
    }
};

// Client的接口实现
class ClientSocket : public Socket
{
public:
    ClientSocket(std::string &ip, in_port_t port)
        : _sockfd(default_sockfd), _sa(ip, port), _client_name(client_name)
    {
        // client[ip][port][fd]#
        _client_name += "[";
        _client_name += _sa.ip();
        _client_name += "]";
        _client_name += "[";
        _client_name += std::to_string(_sa.port());
        _client_name += "]";
    }
    // 创建套接字
    virtual void SocketCreate()
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        CheckRet(_sockfd, _client_name, func_types[0]);
    }
    // 请求连接
    virtual void SocketConnect()
    {
        int ret_connect = connect(_sockfd, (const sockaddr *)(&_sa.addr_in()), _sa.len());
        CheckRet(ret_connect, _client_name, func_types[6]);
    }
    // 接收数据
    virtual void Recv(std::string &recstr)
    {
        char recv_buffer[BUFFERSIZE];
        int ret_recv = recv(_sockfd, recv_buffer, sizeof(recv_buffer), 0);
        CheckRet(ret_recv, _client_name, func_types[4]);
        recv_buffer[ret_recv] = 0;
        recstr += recv_buffer;
    }
    // 发送数据
    virtual void Send(std::string sendstr)
    {
        int ret_send = send(_sockfd, sendstr.c_str(), sendstr.size(), 0);
        CheckRet(ret_send, _client_name, func_types[5]);
    }
    // 拿fd
    virtual int GetSockfd() { return _sockfd; }

private:
    int _sockfd;
    Sockaddr _sa;
    std::string _client_name;

    virtual void SocketBind() {}
    virtual void SocketListen(int backlog) {}
    virtual void SocketAccept() {}
};

// Server的接口实现
class ServerSocket : public Socket
{
public:
    ServerSocket(in_port_t port)
        : _listen_sockfd(default_sockfd), _sockfd(default_sockfd), _sa(port),  _server_name(server_name)
    {
        // client[ip][port][fd]#
        _server_name += "[";
        _server_name += _sa.ip();
        _server_name += "]";
        _server_name += "[";
        _server_name += std::to_string(_sa.port());
        _server_name += "]";
    }

    ~ServerSocket()
    {
    }
    // 创建套接字
    virtual void SocketCreate()
    {
        _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        CheckRet(_listen_sockfd, _server_name, func_types[0]);
    }
    // 绑定套接字
    virtual void SocketBind()
    {
        //解决server主动关闭，无法重启，bind失败的问题
        int opt = 1;
        setsockopt(_listen_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));

        int ret_bind = ::bind(_listen_sockfd, (const sockaddr *)(&_sa.addr_in()), _sa.len());
        CheckRet(ret_bind, _server_name, func_types[1]);
    }
    // 监听，这里调用后，由内核负责，无需用户监听，只要有client请求，系统自动监听到
    virtual void SocketListen(int backlog)
    {
        int ret_listen = ::listen(_listen_sockfd, backlog);
        CheckRet(ret_listen, _server_name, func_types[2]);
    }
    // 获取连接
    virtual void SocketAccept()
    {
        _sockfd = accept(_listen_sockfd, nullptr, nullptr); //获取不到就会阻塞
        CheckRet(_sockfd, _server_name, func_types[3]);
    }
    // 接收数据
    virtual void Recv(std::string &recstr)
    {
        char recv_buffer[BUFFERSIZE];
        int ret_recv = recv(_sockfd, recv_buffer, sizeof(recv_buffer), 0);
        CheckRet(ret_recv, _server_name, func_types[4]);
        recv_buffer[ret_recv] = 0;
        recstr += recv_buffer;
    }
    virtual void Send(std::string sendstr)
    {
        int ret_send = send(_sockfd, sendstr.c_str(), sendstr.size(), 0);
        CheckRet(ret_send, _server_name, func_types[5]);
    }
    // 拿fd
    virtual int GetSockfd() { return _sockfd; }

private:
    int _listen_sockfd;
    int _sockfd;
    Sockaddr _sa;
    std::string _server_name;

    virtual void SocketConnect() {}
};
